#include "piece.h"

/*******************************************************************************
* Constructors
*******************************************************************************/
Piece::Piece(unsigned piece_id, unsigned piece_size)
{
	// initialize data
	m_pieceid = piece_id;
	m_piecesize = piece_size;

	m_data = (unsigned char*)malloc(sizeof(unsigned char) * m_piecesize);
	memset(m_data, 0, sizeof(m_data));

	m_blocksize = (piece_size > BLOCK_SIZE) ? BLOCK_SIZE : piece_size;

	m_numblocks = ceil(((float)m_piecesize / (float)(m_blocksize)));

	m_bitfield = (unsigned char*)malloc(sizeof(unsigned char) * m_numblocks);
	memset(m_bitfield, 0, m_numblocks);
}
Piece::~Piece()
{
//	cout<<"piece deleted"<<endl;
	if (m_data != NULL)
		free(m_data);
	if (m_bitfield != NULL)
		free(m_bitfield);
}

/*******************************************************************************
* Piece Data
*******************************************************************************/
unsigned Piece::GetPieceID()
{
	return m_pieceid;
}
unsigned Piece::GetBlockSize(unsigned block_num)
{
	unsigned ret;
	if (block_num < m_numblocks-1)
		ret = m_blocksize;
	else
		ret = m_piecesize - m_blocksize*(m_numblocks-1);
	return ret;
}
unsigned Piece::GetNumBlocks()
{
	return m_numblocks;
}

/*******************************************************************************
* Peer use only
*******************************************************************************/
bool Piece::CompareHashValue(unsigned char *hash_value)
{
	// compute sha1 hash value
	SHA1Context sha;
	SHA1Reset(&sha);
	SHA1Input(&sha, m_data, m_piecesize);
	SHA1Result(&sha);

	// Swap Endian
	unsigned flipper[5];
	for (int i = 0; i < 5; i++)
	{
		flipper[i] = SwapEndian(&(sha.Message_Digest[i]));
	}

	// print hash values
	/*for (int i = 0; i < 20; i++)
	{
		cout << (int)(hash_value[i] & 0x000000FF) << " ";
	}
	cout << endl;
	for (int i = 0; i < 20; i++)
	{
		cout << (int)(((unsigned char*)flipper)[i] & 0x000000FF) << " ";
	}
	cout << endl;*/

	// compare hash values
	if (memcmp(hash_value, flipper, 20) != 0)
	{
		return false;
	}
	return true;
}
bool Piece::StoreBlock(unsigned block_num, unsigned char *data)
{
	memcpy(m_data+(block_num*m_blocksize), data, this->GetBlockSize(block_num));
	return true;
}
bool Piece::WriteToStorage(Storage *storage)
{
	return storage->store(m_pieceid, m_piecesize, (char*)m_data);
}

void Piece::SetData(unsigned char * data, unsigned len)
{
	memcpy(m_data,data,len);
}
